package api;

import com.fasterxml.jackson.databind.ObjectMapper;
import common.CodeInValidException;
import common.ProblemNotFoundException;
import compile.Answer;
import compile.Question;
import compile.Task;
import dao.Problem;
import dao.ProblemDAO;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Objects;

/**
 * @author 23050
 * @version 1.0
 * @description: 编译用户的代码
 * @date 2023/12/23 9:49
 */
@WebServlet("/compile")
public class CompileServlet extends HttpServlet {

    static class CompileRequest{
        public int id;
        public String code;
    }

    static class CompileResponse{
        //1：编译出错
        //2：运行异常
        //3：其他异常
        public int error;
        public String reason;
        public String stdout;
    }

    private ObjectMapper objectMapper = new ObjectMapper();



    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取到smartTomcat的工作目录
        System.out.println("工作目录："+System.getProperty("user.dir"));
        CompileRequest compileRequest = null;
        CompileResponse compileResponse = new CompileResponse();
        try{
            resp.setContentType("application/json;charset=utf8");
            resp.setStatus(200);
            //1.读取请求的正文，按照json格式进行解析
            String body = readBody(req);
            //将json格式转换成类对象
            compileRequest = objectMapper.readValue(body, CompileRequest.class);
            //2.根据id从数据库中查找题目的详情-》得到测试用例代码
            ProblemDAO problemDao = new ProblemDAO();
            Problem problem = problemDao.selectOne(compileRequest.id);
            if (problem==null){
                //为了统一处理错误，抛出异常
                throw new ProblemNotFoundException();

            }
            String testCode = problem.getTestCode(); //这道题的测试代码
            String requestCode = compileRequest.code;//用户提交的代码
            //3.把用户提交的代码和测试用例代码，给拼接成一个完整的代码
            String finalCode = mergeCode(requestCode, testCode);
//            System.out.println(finalCode);
            if (finalCode==null){
                throw new CodeInValidException();
            }
            //4.创建一个Task实例，调用里面的compile来进行编译
            Task task = new Task();
            Question question = new Question();
            question.setCode(finalCode);
            Answer answer = task.compileAndRun(question);
            //5.根据task的运行结果，包装成一个HTTP相应
            compileResponse.error = answer.getError();
            compileResponse.reason = answer.getReason();
            compileResponse.stdout = answer.getStdout();
//            String respString = objectMapper.writeValueAsString(compileResponse);
//            resp.getWriter().write(respString);

        }catch (ProblemNotFoundException e){
            //处理题目没有找到的异常
            compileResponse.error = 3;
            compileResponse.reason = "没有找到指定的题目"+compileRequest.id;
        }catch (CodeInValidException e){
            //处理题目没有找到的异常
            compileResponse.error = 3;
            compileResponse.reason = "提交的代码不和要求";
        }finally {
            String respString = objectMapper.writeValueAsString(compileResponse);
            resp.getWriter().write(respString);
        }

    }

    private static String mergeCode(String requestCode, String testCode) {
        int pos = requestCode.lastIndexOf("}");
        if (pos == -1){
            //提交的代码不对
            return null;
        }
        return requestCode.substring(0,pos)+testCode+"\n}";
    }


    private static String readBody(HttpServletRequest req) throws UnsupportedEncodingException {
        //1.先根据请求头里面的contentLength来获取body的长度
        int contentLength = req.getContentLength();
        //2.按照这个长度，准备好一个byte[]
        byte[] buffer = new byte[contentLength];
        //3.通过req里面的getInputStream方法，来获取body的流对象
        try (InputStream inputStream =  req.getInputStream()){
            //4.基于这个流对象，读取内容，然后把内容放到byte[]数组中即可
            inputStream.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //5.把byte[]的内容构造成一个String
        return new String(buffer,"utf8");

    }


}





















